package com.cloudkinto.service.user.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cloudkinto.common.constant.GlobalConstants;
import com.cloudkinto.common.constant.SysConstant;
import com.cloudkinto.common.exception.BizException;
import com.cloudkinto.dao.DicBusinessItemDao;
import com.cloudkinto.dao.WxUserDao;
import com.cloudkinto.entity.*;
import com.cloudkinto.service.user.WxUserService;
import com.cloudkinto.service.user.wxvo.SendTempMsgResponse;
import com.cloudkinto.service.user.wxvo.WxTempMsgEntity;
import com.cloudkinto.service.user.wxvo.WxTokenByCodeEntity;
import com.cloudkinto.utils.SecuritySHA1Utils;
import okhttp3.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.net.ssl.*;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * service实现类
 * </p>
 *
 * @author zhangyy
 * @since 2020-10-10
 */
@Service
@Transactional(rollbackFor = Exception.class)//事务回滚
public class WxUserServiceImpl extends ServiceImpl<WxUserDao, WxUserDo> implements WxUserService {
    @Autowired
    private WxUserDao dao;
    @Autowired
    private DicBusinessItemDao dicBusinessItemDao;
    @Autowired
    private RedisTemplate redisTemplate;
    private String WChat_SESSION_TOKEN = "WChat_SESSION_TOKEN";
    private String WChat_JSAPI_TICKET = "WChat_JSAPI_TICKET";
    private String WX_POWER_ID = "WX_POWER_ID:";


    @Override
    public WxTokenByCodeEntity getAccessTokenByCode(String code) {
        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + GlobalConstants.APP_ID_WX + "&secret=" + GlobalConstants.APP_Serect_WX +
                "&code=" + code + "&grant_type=authorization_code";
        String body = okHttpRequestGet(url);
        WxTokenByCodeEntity wxTokenByCodeEntity = JSONObject.parseObject(body, WxTokenByCodeEntity.class);
        if (wxTokenByCodeEntity == null || (wxTokenByCodeEntity.getOpenid() == null && wxTokenByCodeEntity.getAccess_token() == null)) {
            System.out.println(JSONObject.parseObject(body).getIntValue("errcode"));
            System.out.println(JSONObject.parseObject(body).getIntValue("errcode") == 40163);
            if (JSONObject.parseObject(body).getString("errmsg").contains("code")) {
                throw new BizException("301", JSONObject.parseObject(body).getString("errmsg"));
            }
        }else {
            redisTemplate.opsForValue().set(WChat_SESSION_TOKEN, wxTokenByCodeEntity.getAccess_token(), wxTokenByCodeEntity.getExpires_in(), TimeUnit.SECONDS);
        }
        return wxTokenByCodeEntity;
    }


    @Override
    public String getAccessToken() {
        String token = (String) redisTemplate.opsForValue().get(WChat_SESSION_TOKEN);
        if (token == null) {
            String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + GlobalConstants.APP_ID_WX + "&secret=" + GlobalConstants.APP_Serect_WX;
            String body = okHttpRequestGet(url);

            token = JSONObject.parseObject(body).getString("access_token");
            Long expiresTime = JSONObject.parseObject(body).getLong("expires_in");
            redisTemplate.opsForValue().set(WChat_SESSION_TOKEN, token, expiresTime, TimeUnit.SECONDS);
        }
        return token;
    }

    @Override
    public WxUserDo getUserInfoByToken(String access_token, String openid, Long userId, Long companyId) {
        String url = "https://api.weixin.qq.com/sns/userinfo?access_token=" + access_token + "&openid=" + openid + "&lang=zh_CN";
        String body = okHttpRequestGet(url);
        WxUserDo userInfoEntity = JSONObject.parseObject(body, WxUserDo.class);
        userInfoEntity.setUserId(userId);
        userInfoEntity.setCompanyId(companyId);
        addOrUpdate(userInfoEntity);
        return userInfoEntity;
    }

    @Override
    public WxUserDo getUserInfoCommonByToken(String openid) {
        String url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + getAccessToken() + "&openid=" + openid + "&lang=zh_CN";
        String body = okHttpRequestGet(url);
        WxUserDo userInfoEntity = JSONObject.parseObject(body, WxUserDo.class);
        if (userInfoEntity.getSubscribe() == 0) throw new BizException("300", "请先关注公众号");
        addOrUpdate(userInfoEntity);
        return userInfoEntity;
    }

    private void addOrUpdate(WxUserDo userInfoEntity) {
        LambdaQueryWrapper<WxUserDo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(WxUserDo::getUserId, userInfoEntity.getUserId());
        wrapper.eq(WxUserDo::getUserType, SysConstant.DELETE_FLAG_FALSE);
        WxUserDo wxUserDo = dao.selectOne(wrapper);
        userInfoEntity.setUserType(SysConstant.DELETE_FLAG_FALSE);
        if (wxUserDo == null) {
            dao.insert(userInfoEntity);
        } else {
            userInfoEntity.setId(wxUserDo.getId());
            dao.updateById(userInfoEntity);
        }
    }

    @Override
    public Map getJSDKSign(String url) {
        String ticket = getTicket(getAccessToken());
        String noncestr = "Wm3WZYTPz0wzccnW";
        //noncestr=Wm3WZYTPz0wzccnW
        //jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg
        //timestamp=1414587457
        //url=http://mp.weixin.qq.com?params=value
        if (StringUtils.isEmpty(ticket)) throw new BizException("ticket is null");
        long timeMillis = System.currentTimeMillis();
        String origionData = "jsapi_ticket=" + ticket + "&noncestr=" + noncestr + "&timestamp=" + timeMillis + "&url=" + url;
        String signature = null;
        try {
            signature = SecuritySHA1Utils.shaEncode(origionData);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BizException("signature is failure");
        }
        Map hashMap = new HashMap();
        hashMap.put("timestamp", timeMillis);
        hashMap.put("signature", signature);
        hashMap.put("noncestr", noncestr);
        hashMap.put("origiondata", origionData);
        return hashMap;
    }

    private String getTicket(String accessToken) {
        String ticket = (String) redisTemplate.opsForValue().get(WChat_JSAPI_TICKET);
        if (ticket == null) {
            String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + accessToken + "&type=jsapi";
            String body = okHttpRequestGet(url);
            try {
                ticket = JSONObject.parseObject(body).getString("ticket");
                Long expiresTime = JSONObject.parseObject(body).getLong("expires_in");
                redisTemplate.opsForValue().set(WChat_JSAPI_TICKET, ticket, expiresTime, TimeUnit.SECONDS);
            } catch (Exception e) {
                e.printStackTrace();
                throw new BizException(body);
            }
        }
        return ticket;
    }

    public static String okHttpRequestGet(String requestUrl) {
        OkHttpClient.Builder builder = getUnsafeOkHttpClient().newBuilder();
        builder.connectTimeout(60, TimeUnit.SECONDS)
                .readTimeout(60, TimeUnit.SECONDS)
                .writeTimeout(60, TimeUnit.SECONDS)
                .retryOnConnectionFailure(false);
        Request request = new Request.Builder()
                .url(requestUrl)
                .build();
        Response response = null;
        String body = "";
        try {
            System.out.println(requestUrl);
            response = builder.build().newCall(request).execute();
            body = response.body().string();
            System.out.println(body);
        } catch (
                IOException e) {
            e.printStackTrace();
        }
        return body;
    }

    @Override
    public void orderInput(OrderInputDo orderInputDo) {
        WxTempMsgEntity wxTempMsgEntity = new WxTempMsgEntity();
        wxTempMsgEntity.setFirst("您有新的入库单提醒");
        wxTempMsgEntity.setKeyword1(orderInputDo.getOrderInputNumber());
        wxTempMsgEntity.setRemark("请及时查收");
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("user_id", orderInputDo.getCreateBy());
        wrapper.eq("user_type", SysConstant.DELETE_FLAG_FALSE);
        List<WxUserDo> userInfoEntities = dao.selectList(wrapper);
        if (!CollectionUtils.isEmpty(userInfoEntities)) {
            for (WxUserDo userInfo : userInfoEntities) {
                sendTemMsg(wxTempMsgEntity, userInfo.getOpenid(), 1);
            }
        }
    }

    @Override
    public void firstVessel(FirstVesselOrderDo firstVesselOrderDo) {
        WxTempMsgEntity wxTempMsgEntity = new WxTempMsgEntity();
        wxTempMsgEntity.setFirst("您有新的fba头程订单提醒");
        wxTempMsgEntity.setKeyword1(firstVesselOrderDo.getOrderNumber());
        DicBusinessItemDo businessItemDo = dicBusinessItemDao.selectById(firstVesselOrderDo.getStatus());
        if (businessItemDo != null) {
            wxTempMsgEntity.setKeyword2(businessItemDo.getDicItemValue());
        }
        wxTempMsgEntity.setRemark("请及时查收");
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("user_id", firstVesselOrderDo.getCreateBy());
        wrapper.eq("user_type", SysConstant.DELETE_FLAG_FALSE);
        List<WxUserDo> userInfoEntities = dao.selectList(wrapper);
        if (!CollectionUtils.isEmpty(userInfoEntities)) {
            for (WxUserDo userInfo : userInfoEntities) {
                sendTemMsg(wxTempMsgEntity, userInfo.getOpenid(), 2);
            }
        }
    }

    @Override
    public void orderBack(OrderBackDo orderBackDo) {
        WxTempMsgEntity wxTempMsgEntity = new WxTempMsgEntity();
        wxTempMsgEntity.setFirst("您有新的退货订单提醒");
        wxTempMsgEntity.setKeyword1(orderBackDo.getOrderOutNumber());
        wxTempMsgEntity.setRemark("请及时查收");
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("user_id", orderBackDo.getCreateBy());
        wrapper.eq("user_type", SysConstant.DELETE_FLAG_FALSE);
        List<WxUserDo> userInfoEntities = dao.selectList(wrapper);
        if (!CollectionUtils.isEmpty(userInfoEntities)) {
            for (WxUserDo userInfo : userInfoEntities) {
                sendTemMsg(wxTempMsgEntity, userInfo.getOpenid(), 1);
            }
        }

    }

    @Override
    public void sendAvailableBalanceTemMsg(CompanyAccountDo companyAccountDo, int remainDays) {
        WxTempMsgEntity wxTempMsgEntity = new WxTempMsgEntity();
        wxTempMsgEntity.setFirst("您的余额预计还可使用" + remainDays + "天");
        wxTempMsgEntity.setKeyword1(companyAccountDo.getCompanyAccount() + "円");
//        wxTempMsgEntity.setKeyword2(dateTimeFormat);
        wxTempMsgEntity.setRemark("请注意，欠款后将不能使用出库功能");
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("company_id", companyAccountDo.getCompanyId());
        wrapper.eq("user_type", SysConstant.DELETE_FLAG_FALSE);
        List<WxUserDo> userInfoEntities = dao.selectList(wrapper);
        if (!CollectionUtils.isEmpty(userInfoEntities)) {
            for (WxUserDo userInfo : userInfoEntities) {
                sendTemMsg(wxTempMsgEntity, userInfo.getOpenid(), 1);
            }
        }
    }


    @Override
    public String sendTemMsg(WxTempMsgEntity wxTempMsgEntity, String toUser, int type) {
        String tempId = "";
        if (type == 1) {
            tempId = "AqPsVsqgEFX9-HkK2hCTYmPSiSsAt8y61hSKyQ3pXT0";
        } else if (type == 2) {
            tempId = "PYM7uBbnwHl7XJPuVZAZnLBkidYufin4mC0V-kl03kA";
        } else if (type == 3) {
            tempId = "7k7ONn9TaTvlf-N5hbibMzSs6GLdKjhEcfwkymVM_fo";
        }
        return sendTemMsg(wxTempMsgEntity, toUser, tempId);
    }

    @Override
    public String sendTemMsg(WxTempMsgEntity wxTempMsg, String touser, String tempId) {
        String url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + getAccessToken();
        Map map = new HashMap();
        map.put("touser", touser);
        map.put("template_id", tempId);
        map.put("url", "");
        map.put("data", JSONObject.toJSON(wxTempMsg));
        int count = 0;
        String body = okHttpRequestPost(url, JSONObject.toJSONString(map));
        SendTempMsgResponse response = JSONObject.parseObject(body, SendTempMsgResponse.class);
        if (response.errorcode == 0) {

        } else if (response.errorcode == 40001) {//token过期
            count++;
            body = sendTemMsg(wxTempMsg, touser, tempId);
            if (count > 3) return body;
        }
        return body;
    }

    public static String okHttpRequestPost(String requestUrl, String outputStr) {
        OkHttpClient.Builder builder = getUnsafeOkHttpClient().newBuilder();
        builder.connectTimeout(60, TimeUnit.SECONDS)
                .readTimeout(60, TimeUnit.SECONDS)
                .writeTimeout(60, TimeUnit.SECONDS)
                .retryOnConnectionFailure(false);
        //        System.getProperties().put("proxySet", "true");
//        System.getProperties().put("proxyHost", "127.0.0.1");
//        System.getProperties().put("proxyPort", "1080");
        Request request = new Request.Builder()
                .addHeader("Content-type", "application/json")
                .url(requestUrl)
                .method(HttpMethod.POST.name(), RequestBody.create(MediaType.get("application/json"), outputStr))
                .build();
        System.out.println(outputStr);
        Response response = null;
        String body = "";
        try {
            response = builder.build().newCall(request).execute();
            body = response.body().string();
            System.out.println(body);
        } catch (
                IOException e) {
            e.printStackTrace();
        }
        return body;
    }

    //okHttp3添加信任所有证书

    public static OkHttpClient getUnsafeOkHttpClient() {
        try {
            final TrustManager[] trustAllCerts = new TrustManager[]{
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {
                        }

                        @Override
                        public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {
                        }

                        @Override
                        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                            return new java.security.cert.X509Certificate[]{};
                        }
                    }
            };
            final SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
            final javax.net.ssl.SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
            OkHttpClient.Builder builder = new OkHttpClient.Builder();
            builder.sslSocketFactory(sslSocketFactory);
            builder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });

            return builder.build();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
